/*
 * @Description: 跳转权限-路由前置钩子
 * @Author: HuiSir<273250950@qq.com>
 * @Date: 2021-09-17 19:28:46
 * @LastEditTime: 2025-09-03 10:46:11
 */
import { currentAdmin } from "@/api/sys";
import { NavigationGuardWithThis } from "vue-router";
import { useAdminStore, useLayoutStore, useGetters } from "@/store";
import PageLoading from "@/utils/PageLoading";

const useBeforeEach: NavigationGuardWithThis<void> = async (to, from, next) => {
  // 当前路由无效
  // 阻止路由跳转在前置钩子中处理，这里`next(false)`会触发后置钩子中的`failure`错误
  // 在后置钩子中判断第三参数`failure`，及时中止就可以
  // 使用`fullPath`判断可以排除相同`query`参数的路由
  if (to.fullPath !== "/" && to.fullPath === from.fullPath) {
    next(false);
    return;
  }

  // 加载loading
  PageLoading.show();

  // store
  const adminStore = useAdminStore();
  const layoutStore = useLayoutStore();
  const getters = useGetters();

  // 若跳登录页，则清除登陆状态，直接跳转
  if (to.name === "Login") {
    // 清除登录状态
    adminStore.clearLoginState();
    // 清除菜单和路由
    adminStore.clearAllMenuAndRoute();
    // 清除TAB路由
    layoutStore.clearHistoryRoute();
    next();
    return;
  }

  /**
   * 外站进入、第一次打开、刷新网页
   */
  if (from.fullPath === "/" && !from.name) {
    //获取token
    const Token: string = getters.getToken;

    // 有token说明已登录(这里是获取不到登录状态的，只能通过token判断)
    if (Token) {
      // 登录信息
      const adminInfo = adminStore.adminInfo;

      // 没有管理员信息，说明没有查询过，则查询一次（这里考虑到管理员菜单转为路由后需要再次重定向一次）
      if (!adminInfo) {
        // 查询管理员信息
        const { ok, data } = await currentAdmin();

        // 查询若有错误会在axios全局配置钩子中处理
        if (ok) {
          // 管理员信息处理
          adminStore.loginResHandler(data);

          // 由于动态路由的缘故，这里重新定向
          next({ ...to, replace: true });
        } else {
          // 如果这里查询完成，登录状态有问题，则直接跳转到登录页
          // redirect要携带全量参数fullPath，需转义
          next("/login?redirect=" + encodeURIComponent(to.fullPath));
        }

        return;
      } else {
        // 重定向后结果
        // adminStore.isLogin => 登录状态（这里查询的登录状态包含已经查询过的结果）
        // 该页面必须要登陆，且现在为未登录状态，则跳转到登录页
        // 若为路由正常跳转时发现未登录，则弹出登录框，而不是跳转到登录页，后面处理
        // 只有当动态路由已添加之后，下次再走到这儿，才能查到to.meta，所以放到adminInfo已赋值之后
        if (to.meta.internal && !adminStore.isLogin) {
          // redirect要携带全量参数fullPath，需转义
          next("/login?redirect=" + encodeURIComponent(to.fullPath));
          return;
        }
      }
    } else {
      // 没有token情况下,跳转登录页
      // redirect要携带全量参数fullPath，需转义
      next("/login?redirect=" + encodeURIComponent(to.fullPath));
      return;
    }
  }

  /* 路由正常跳转 */

  // 如果未登录
  if (to.meta.internal && !adminStore.isLogin) {
    //登陆失效，弹出登陆框
    adminStore.LoginInvalid();

    // 避免未登录状态下历史TAB的插入，这个在路由后置钩子中处理

    // 这里不跳转
    next(false);
    return;
  }

  /* 关于权限验证 */
  // 若该管理员没有访问该路由的权限，则请求回来的路由中不会包含该路由信息，则访问时会重定向到404页面
  // 若请求回的路由中已有该路由信息，但中途被管理员卸去了权限，则通过接口请求来验证权限
  // 在接口携带的token中添加菜单的ID信息，管理端通过该管理员角色信息中的权限信息与菜单ID进行匹配，若匹配失败，则返回无权限
  // 当然在后端验证菜单的权限时，也要判断菜单是否已在中途被删除或被停用（status字段）
  // 所以权限相关验证放到请求钩子中，这里无需考虑

  // 正常情况直接跳转
  next();
};

export default useBeforeEach;
